Trong bài Xây dựng truy vấn bằng Laravel Query Builder chúng ta có một ví dụ trong đó tạo một trang chứa danh sách các sản phẩm. Danh sách này có 4 sản phẩm nên chưa cần phân trang, nếu số lượng sản phẩm lên đến vài chục sản phẩm, chúng ta cần phân trang, mỗi trang sẽ chỉ chứa 5 sản phẩm giúp cho quản lý tốt hơn. Laravel Pagination giúp cho việc phân trang ngay khi xây dựng các truy vấn một cách rất dễ dàng, ngoài ra tính năng phân trang này còn tự sinh mã HTML phù hợp với cách thiết kế trang web sử dụng Bootstrap.
Phân trang kết quả truy vấn trong Laravel
Laravel sử dụng phương thức paginate() để phân trang, xem ví dụ sau để hiểu hơn cách sử dụng:
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$products = DB::table('products')->paginate(5);
return view('fontend.product.list')->with($products);
}
phương thức paginate() có thể sử dụng cho cả Query Builder và Eloquent ORM, nó tự động tính toán số lượng trang, các bản ghi nào thuộc trang… Trang hiện tại sẽ được phát hiện trong qua tham số page trong query string của URL. Hiển thị kết quả phân trang trong view chỉ đơn giản như sau (sửa luôn view list.blade.php trong resources/views/fontend/product):
@extends('layouts.default')
@section('title', 'Danh sách sản phẩm')
@section('content')
<table class="table table-bordered">
<tr class="success">
<th>ID</th>
<th>Tên sản phẩm</th>
<th>Giá sản phẩm</th>
<th>Nội dung</th>
<th>Ảnh sản phẩm</th>
<th>Đăng bán</th>
<th>Action</th>
</tr>
@foreach($products as $p)
<tr>
<td>{{ $p->id }}</td>
<td>{{ $p->name }}</td>
<td class="text-right">{{ number_format($p->price) }}</td>
<td>{{ $p->content }}</td>
<td>
<img src="{{ Asset($p->image_path) }}" alt="{{ $p->name }}" width="120" height="120">
</td>
<td>
@if($p->active)
<span class="text-success glyphicon glyphicon-ok"></span>
@else
<span class="text-danger glyphicon glyphicon-remove"></span>
@endif
</td>
<td>
<a href="{{ '/product/' . $p->id . '/edit'}}"><span class="glyphicon glyphicon-pencil">Edit</span></a>
<a href="{{ '/product/' . $p->id }}"><span class="glyphicon glyphicon-trash">Delete</span></a>
</td>
</tr>
@endforeach
</table>
{{ $products->links() }}
@endsection
Chúng ta thấy việc chèn vào kết quả phân trang chỉ đơn giản là thêm
{{ $products->links() }}
Chúng ta nhập thêm một số sản phẩm nữa cho danh sách hơn 5 sản phẩm và vào lại trang danh sách sản phẩm http://laravel.dev/product xem phân trang thế nào. Các URL trong phân trang sẽ có dạng http://laravel.dev/product?page=x, x là trang hiện hành. Nếu bạn muốn thêm các tham số query string vào URL này, sử dụng phương thức appends(), ví dụ bạn muốn phân trang các sản phẩm có giá từ 300k đến 600k chẳng hạn, đường dẫn sẽ có dạng http://laravel.dev/product?page=x&minprice=300000&maxprice=600000.
{{ $products->appends(['minprice' => 300000, 'maxprice' => 600000])->links() }}
Chỉnh sửa giao diện phân trang
Như đã nói ở phần đầu, mặc định giao diện phần phân trang trong Laravel Pagination tạo ra mã HTML tương thích với Bootstrap, chính vì vậy nếu bạn không sử dụng Bootstrap làm CSS framework chính của project bạn có thể chỉnh sửa giao diện phần phân trang như sau:
{{ $products->links('pagination') }}
với pagination.blade.php là một view nằm trong resources/views, chúng ta cũng hoàn toàn có thể truyền tham số cho view này bằng cách:
{{ $products->links('view.pagination', ['minprice' => 300000, 'maxprice' => 600000]) }}
Một cách khác để chỉnh sửa giao diện phần phân trang là chỉnh sửa ngay trên chính view mặc định của Laravel bằng cách export chúng vào thư mục resouces/views/vendor sử dụng câu lệnh
php artisan vendor:publish --tag=laravel-pagination
Câu lệnh này sẽ export ra một view default.blade.php nằm trong resouces/views/vendor/pagination và bạn chỉ đơn giản là chỉnh sửa các mã HTML và CSS trong view này.
Các phương thức khác sử dụng trong Laravel Pagination
Laravel còn cung cấp một số phương thức khác liên quan đến phân trang, các phương thức này có thể sử dụng khi bạn muốn xây dựng giao diện phần phân trang riêng.
$products = DB::table('products')->where('active', '=', 1)->paginate(5);
// Số trang trong kết quả $products trả về
$products->count()
// Trang hiện tại trong phần phân trang
$results->currentPage()
$results->firstItem()
$results->hasMorePages()
$results->lastItem()
// Trang cuối cùng trong phân trang
$results->lastPage()
// Trang tiếp theo trong phân trang
$results->nextPageUrl()
$results->perPage()
// Trang trước đó trong phân trang
$results->previousPageUrl()
$results->total()
$results->url($page)